var games = {
    Breakaway: function (canvas) {
        var _game = this;
        var _graphics = new ctk.Graphics(canvas);
        var _canvasWidth = _graphics.getWidth();
        var _canvasHeight = _graphics.getHeight();
        var _timeoutId;
        var _rows = 4;
        var _cols = 7;
        var _bricks = [];
        var _brickWidth = 1;
        var _brickHeigth = 1;
        var _paddleX = 0;
        var _paddleY = 0;
        var _paddleSpeed = 1;
        var _paddleWidth = 1;
        var _paddleHeight = 1;
        var _paddleGoingRight = false;
        var _paddleGoingLeft = false;
        var _ballX = 0;
        var _ballY = 0;
        var _ballDX = 7;
        var _ballDY = -7;
        var _ballRadius = 1;
        var _level = 1;
        var _baseSpeed = 7;


        function log(message) {
            if (window.console && window.console.log) {
                window.console.log(message);
            }
        }

        window.document.onkeydown = function (e) {
            var left = 37;
            var right = 39;
            var keyCode = (e && e.which) ? e.which : window.event.keyCode;

            switch (keyCode) {
                case left: _paddleGoingLeft = true; break;
                case right: _paddleGoingRight = true; break;
            }
        };

        window.document.onkeyup = function (e) {
            var left = 37;
            var right = 39;
            var sKey = 83;
            var keyCode = (e && e.which) ? e.which : window.event.keyCode;

            switch (keyCode) {
                case left: _paddleGoingLeft = false; break;
                case right: _paddleGoingRight = false; break;
                case sKey: _game.start(); break;
            }
        };

        function clear() {
            _graphics.clearRect(0, 0, _canvasWidth, _canvasHeight);
        }

        function paintBall() {
            _graphics.setColor("#999900");
            _graphics.fillCircle(_ballX, _ballY, _ballRadius);
        }

        function paintBrick(x, y, width, height) {
            var widthInset = 2;
            var heightInset = 2;

            // draw brick outline
            _graphics.setColor("#cccccc");
            _graphics.fillRect(x, y, width, height);

            // draw brick body
            _graphics.setColor("#880000");
            _graphics.fillRect(x + widthInset, y + heightInset, width - widthInset * 2, height - heightInset * 2); // inner
        }

        function paintBricks() {
            var x = 0;
            var y = 0;

            for (var row = 0; row < _rows; row++) {
                x = 0;
                for (var col = 0; col < _cols; col++) {
                    if (_bricks[row][col]) {
                        paintBrick(x, y, _brickWidth, _brickHeigth);
                    }
                    x += _brickWidth;
                }

                y += _brickHeigth;
            }
        }

        function paintPaddle() {
            _graphics.setColor("#000088");
            _graphics.fillRect(_paddleX, _paddleY, _paddleWidth, _paddleHeight);
        }

        function initializeBricks() {
            _bricks = [];
            for (var row = 0; row < _rows; row++) {
                _bricks.length++;
                _bricks[row] = [];
                for (var col = 0; col < _cols; col++) {
                    _bricks[row].length++;
                    _bricks[row][col] = true; //true indicates active
                }
            }
        }

        function hasBricksRemaining() {
            for (var row = 0; row < _rows; row++) {
                for (var col = 0; col < _cols; col++) {
                    if (_bricks[row][col]) {
                        return true;
                    }
                }
            }

            return false;
        }

        function intersects(x1, y1, width1, height1, x2, y2, width2, height2) {
            var xAligned = false;
            var yAligned = false;

            if (x1 >= x2 && x1 <= x2 + width2) {
                xAligned = true;
            } else if (x1 + width1 >= x2 && x1 + width1 <= x2 + width1) {
                xAligned = true;
            }

            if (y1 >= y2 && y1 <= y2 + height2) {
                yAligned = true;
            } else if (y1 + height1 >= y2 && y1 + height1 <= y2 + height1) {
                yAligned = true;
            }

            return xAligned && yAligned;
        }

        function handleCollisions() {
            var transformedBallX = _ballX;
            var transformedBallY = _ballY;
            var ballDiameter = _ballRadius * 2;

            // Deflect ball on x-axis
            if ((transformedBallX <= 0) || (_ballX + ballDiameter >= _canvasWidth)) {
                _ballDX = -_ballDX;
            }

            // Deflect ball on y-axis
            if (transformedBallY <= 0) {
                _ballDY = -_ballDY;
            }


            // Detect collision with paddle
            if (intersects(transformedBallX, transformedBallY, ballDiameter, ballDiameter, _paddleX, _paddleY, _paddleWidth, _paddleHeight)) {
                log("Paddle collision detected");
                _ballDY = -Math.abs(_ballDY);

                // Vary x vector based on location hit on paddle
                var ballCenter = _ballX + _ballRadius;
                var paddleCenter = _paddleX + _paddleWidth / 2;
                var distanceFromCenter = ballCenter - paddleCenter;
                var maxDistanceFromCenter = _paddleWidth / 2;
                _ballDX = distanceFromCenter / maxDistanceFromCenter * _baseSpeed;
            }

            // Detect brick collisions
            var brickX = 0;
            var brickY = 0;
            var collidedWithBrick = false;
            for (var row = 0; row < _rows; row++) {
                brickX = 0;
                for (var col = 0; col < _cols; col++) {
                    if ((_bricks[row][col]) && ((intersects(transformedBallX, transformedBallY, ballDiameter, ballDiameter, brickX, brickY, _brickWidth, _brickHeigth)))) {
                        log("Brick collision detected");
                        _bricks[row][col] = false;

                        // Deflect ball
                        _ballDY = -_ballDY;
                        collidedWithBrick = true;
                        break;
                    }
                    brickX += _brickWidth;
                }

                if (collidedWithBrick) {
                    break;
                }
                brickY += _brickHeigth;
            }

            // Ball dropped.  Game over
            if (transformedBallY + ballDiameter >= _canvasHeight) {
                _game.stop();
                log("Game over");
            }
        }

        function paint() {
            clear();
            paintBricks();
            paintBall();
            paintPaddle();
        }

        this.update = function () {
            // Update ball coordinates
            _ballX = Math.max(0, Math.min(_canvasWidth - _ballRadius * 2, _ballX + _ballDX));
            _ballY = Math.max(0, Math.min(_canvasHeight - _ballRadius * 2, _ballY + _ballDY));

            // Update paddle coordinates
            if (_paddleGoingLeft) {
                _paddleX = Math.max(0, Math.min(_canvasWidth, _paddleX - _paddleSpeed));
            } else if (_paddleGoingRight) {
                _paddleX = Math.max(0, Math.min(_canvasWidth - _paddleWidth, _paddleX + _paddleSpeed));
            }

            handleCollisions();
            paint();

            // Reset game if no more bricks
            if (!hasBricksRemaining()) {
                _game.startLevel(_level + 1);
            }
        };

        function resize() {
            // brick
            _brickWidth = _canvasWidth / _cols;
            _brickHeigth = _canvasHeight / 3 / _rows;

            // ball
            _ballRadius = _canvasWidth * 0.03;

            // paddle
            _paddleWidth = _canvasWidth * 0.2;
            _paddleHeight = _canvasHeight * 0.05;
            _paddleY = _canvasHeight - _paddleHeight;
        }

        function randomizeStartupPositions() {
            // Initilize paddle position
            _paddleX = Math.random() * (_canvasWidth - _paddleWidth);
            _paddleGoingLeft = false;
            _paddleGoingRight = false;

            // Initialize ball position
            _ballX = _paddleX + (_paddleWidth / 2) - _ballRadius;
            _ballY = _paddleY - _ballRadius * 2;

            // Randomize ball direction
            _ballDX = (Math.random() < 0.5) ? -_baseSpeed : _baseSpeed;
        }

        function setLevelProperties(level) {
            log("Setting game level: " + level);
            _level = level;

            var maxBaseSpeed = 15;
            var minSpeed = 2;
            _baseSpeed = Math.min(_level / 2 + minSpeed, maxBaseSpeed);
            _ballDX = _baseSpeed;
            _ballDY = -_baseSpeed;
            _paddleSpeed = _ballDX;
        }

        this.initialize = function () {
            log("Initializing Breakaway by Tony Okorodudu. (c) 2009");
            
            // Resize components
            resize();

            // Reconstruct the bricks
            initializeBricks();

            // Randomize the starting position of the paddle and ball
            randomizeStartupPositions();

            paint();
        };

        this.stop = function () {
            clearTimeout(_timeoutId);
            log("Stopping game");
        };

        this.start = function () {
            this.startLevel(1);
        };

        this.startLevel = function (level) {
            // Reset the timer
            clearInterval(_timeoutId);

            this.initialize();

            setLevelProperties(level);

            // Start timer
            log("Starting game");
            _timeoutId = setInterval(this.update, 20);
        };
    }
};